
#include "./../../io_reuse_module/io_reuse_module_define.h"
#include "./../../log_module/log_module_define.h"
#include "test_util.h"
#include <cstdint>
#include <cstdio>
#include <gtest/gtest.h>
#include <map>
#include <memory>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>

TEST(ModuleTest, Client)
{
    IoEpollFactory factory = {};
    IoReuseModule io_operate(&factory);
    int client_socket = CreateClientSocket();
    {
        io_operate.AddEvent(client_socket, EmIoIn | EmIoOut | EmIoRdHup | EmIoErr | EmIoOneShot);
    }
    while (true)
    {
    
        std::vector<struct EventData> trigger_data;
        int size = io_operate.WaitEvent(trigger_data, -1);
        if (size > 0)
        {
            for (auto & data : trigger_data)
            {
                printf("trigger socket fd : %ld.\n", data.id);
                printf("event & EmIoIn : %d.\n", data.events & EmIoIn);
                printf("event & EmIoOut : %d.\n", data.events & EmIoOut);
                printf("event & EmIoErr : %d.\n", data.events & EmIoErr);
                printf("event & EmIoRdHup : %d.\n\n", data.events & EmIoRdHup);
                if (data.events & EmIoOut) 
                {
                    io_operate.ModEvent(data.id, EmIoIn | EmIoErr | EmIoRdHup | EmIoOneShot);
                }
                if (data.events & EmIoIn)
                {
                    if (data.events & EmIoRdHup)
                    {
                        io_operate.DelEvent(data.id);
                        close(client_socket);
                        client_socket = 0;
                        break; 
                    }
                    else
                    {
                        uint8_t array_data[10];
                        ssize_t read_size = read(client_socket, array_data, sizeof(array_data));
                        if (read_size <= 0)
                        {
                            io_operate.DelEvent(data.id);
                            close(client_socket);
                            client_socket = 0;
                        }
                        else
                        {
                            io_operate.ModEvent(data.id, EmIoIn | EmIoOneShot | EmIoErr | EmIoRdHup);
                        }
                    }
                }
            }
        }
        if (client_socket == 0)
        {
            break;
        }
    }
}
TEST(ModuleTest, Server)
{
    IoEpollFactory factory;
    IoReuseModule io_operate(&factory);
    int64_t listen_id = 0;
    int server_socket = CreateServerSocket();
    {
        listen_id = io_operate.AddEvent(server_socket, EmIoIn | EmIoOut | EmIoRdHup | EmIoErr | EmIoOneShot);
    }
    std::map<int64_t, std::shared_ptr<TcpSocket>> m_socket_map;
    while (true)
    {
        std::vector<struct EventData> trigger_data;
        int size = io_operate.WaitEvent(trigger_data, -1);
        if (size > 0)
        {
            for (auto & data : trigger_data)
            {
                printf("trigger socket fd : %ld.\n", data.id);
                printf("event & EmIoIn : %d.\n", data.events & EmIoIn);
                printf("event & EmIoOut : %d.\n", data.events & EmIoOut);
                printf("event & EmIoErr : %d.\n", data.events & EmIoErr);
                printf("event & EmIoRdHup : %d.\n\n", data.events & EmIoRdHup);
                if (data.id == listen_id)
                {
                    if (data.events & EmIoOut)
                    {
                        io_operate.ModEvent(listen_id, EmIoIn | EmIoErr | EmIoRdHup | EmIoOneShot);
                    }
                    if (data.events & EmIoIn)
                    {
                        int new_client_socket = accept(server_socket, nullptr, nullptr);
                        if (new_client_socket > 0)
                        {
                            auto socket_ptr = std::make_shared<TcpSocket>(new_client_socket);
                            auto index = io_operate.AddEvent(new_client_socket, EmIoIn|EmIoOut|EmIoErr|EmIoRdHup|EmIoOneShot);
                            m_socket_map[index] = socket_ptr; 
                        }
                        io_operate.ModEvent(listen_id, EmIoIn | EmIoErr | EmIoRdHup | EmIoOneShot);
                    }
                }
                else
                { 
                    if (data.events & EmIoOut)
                    {
                        io_operate.ModEvent(data.id, EmIoIn | EmIoErr | EmIoRdHup | EmIoOneShot);
                    }
                    if (data.events & EmIoIn)
                    {
                        if (data.events & EmIoRdHup)
                        {
                            io_operate.DelEvent(data.id);
                            m_socket_map.erase(data.id);
                        }
                        else
                        {
                            uint8_t array_data[10] = {0};
                            int read_size = read(m_socket_map[data.id]->GetSocket(), array_data, sizeof(array_data));
                            if (read_size == 0)
                            {
                                io_operate.DelEvent(data.id);
                                m_socket_map.erase(data.id);
                            }
                            else
                            {
                                io_operate.ModEvent(data.id, EmIoIn | EmIoErr | EmIoRdHup | EmIoOneShot);
                            }
                        }
                    }
                }
            }
        }
    }
}

int main(int argc, char * argv[])
{
    testing::InitGoogleTest(&argc, argv);

    LogModuleConfig config;
    config.m_file_name = argv[0];
    config.m_log_level = "trace";
    LogModule::Instance()->InitModule(config);
    TRACE("testtesttest message line");
    return RUN_ALL_TESTS();
}
